package miscellaneous;

import java.awt.Color;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import mockup.UserMockup;

import client.login.Login;
import client.tcp.ClientTCP;

import data.Appointment;
import data.Invite;
import data.Meeting;
import data.Message;
import data.SynchronizedList;
import data.User;
import data.room.Reservation;
import data.room.Room;

/**
 * List of data stored locally
 * @author daniel
 */
public class Storage {

	private static User loggedInUser;
	private static int sessionID;
	private static ClientTCP socket;
	
	public static final SynchronizedList<Appointment> appointments = new SynchronizedList<Appointment>(Appointment.class);
	public static final SynchronizedList<Meeting> meetings = new SynchronizedList<Meeting>(Meeting.class);
	
	public static final SynchronizedList<User> users = new SynchronizedList<User>(User.class);
	public static final Map<Integer,Room> rooms = new HashMap<Integer,Room>();
	public static final SynchronizedList<Message> messages = new SynchronizedList<Message>(Message.class);
	public static final Map<Integer,Reservation> reservations = new HashMap<Integer,Reservation>();


	// gui colors and settings, final until gui color settings is added
	public static final Color colorAppointmentFill = new Color(210, 210, 250,230);
	public static final Color colorAppointmentOutline = new Color(105,105,125,255);
	public static final Color colorMeetingFillAnswered = new Color(210,250,210,230);
	public static final Color colorMeetingOutlineAnswered = new Color(105,125,105,255);
	public static final Color colorCalendarToday = new Color(230,230,230);
	public static final Color colorCalendarDragFill = new Color(230, 230, 70, 150);
	public static final Color colorCalendarDragOutline = new Color(210,210, 70, 240);
	
	public static final Color colorMeetingFillNotAnswered = new Color(250,230,220,150);
	public static final Color colorMeetingOutlineNotAnswered = new Color(105,125,105,225);
	
	public static final int rectangleArcRadius = 10;
	

	public static User getloggedInUser() {
		return loggedInUser;
	}

	public static int getSessionID() {
		return sessionID;
	}
	
	/**
	 * Sets the logged in user
	 * @param login The login object containing the login information
	 */
	public static boolean setLogin(Login login) {
		if(login != null) {
			if(new Throwable().fillInStackTrace().getStackTrace()[1].getClassName().equals("client.Client") &&
					//now the call has to come from a propertyChange-method to login a user
					new Throwable().fillInStackTrace().getStackTrace()[1].getMethodName().equals("propertyChange")) {
				//now the call has to come from the Client class to login a user
				
				UserMockup userM = login.getUser();
				User user = new User(userM.getId(), userM.getName(), null, userM.getEmail(), userM.getPhone(), userM.getDepartment());
				
				GregorianCalendar cal = new GregorianCalendar(Locale.FRANCE);
				cal.setTimeInMillis(userM.getDateOfBirth());
				
				user.setDateOfBirth(cal);
				
				loggedInUser = user;
				Storage.users.insert(user);
				sessionID = login.getSessionID();
				socket = login.getSocket();
				return true;
			} else {
				System.err.println("The login info did not come through the right channels. Login denied");
				return false;
			}
		} else {
			if(socket != null) {
				if(socket.isConnected())
					socket.closeCon();
				socket = null;
			}
			loggedInUser = null;
			sessionID = -1;
			clearStorage();
			return false;
		}
		
	}

	/**
	 * Clear out all the data from the Storage
	 */
	private static void clearStorage() {
		appointments.clearList();
		meetings.clearList();
		users.clearList();
		rooms.clear();
		reservations.clear();
		messages.clearList();
	}

	public static ClientTCP getSocket() {
		return socket;
	}

	/**
	 * Filters the appointment list to just concern all the
	 * appoitments the a spesici
	 * @param user
	 * @return
	 */
	public static List<Appointment> getUsersAppointments(User user) {
		List<Appointment> list = new ArrayList<Appointment>();
		for(Appointment a : Storage.appointments ) {
			if(a.getOwner() == user) {
				list.add(a);
			} else if(a instanceof Meeting) {
				for(int i = 0; i < messages.size(); i++) {
					if(messages.get(i) instanceof Invite && messages.get(i).getMeeting() == a && 
							messages.get(i).getReceiver() == user && ((Invite)messages.get(i)).getAnswer() != Invite.ANSWER_NO)
						list.add(a);
				}
			}
		}
		return list;
	}
	
	/**
	 * Filters the appointment list to just concern all the
	 * appoitments the a spesici
	 * @param user
	 * @return
	 */
	public static List<Meeting> getUsersMeetings(User user) {
		List<Meeting> list = new ArrayList<Meeting>();
		for(Meeting a : Storage.meetings ) {
			if(a.getOwner() == user) {
				list.add(a);
			}
			for(int i = 0; i < messages.size(); i++) {
				if(messages.get(i) instanceof Invite && messages.get(i).getMeeting() == a && 
						messages.get(i).getReceiver() == user && ((Invite)messages.get(i)).getAnswer() != Invite.ANSWER_NO)
					list.add(a);
			}
		}
		return list;
	}
	
	public static List<Appointment> getUsersAppointments(int userid) {
		for(User u : users) {
			if(u.getId() == userid) {
				return getUsersAppointments(u);
			}
		}
		return null;
	}
	
	public static List<Meeting> getUsersMeetings(int userid) {
		for(User u : users) {
			if(u.getId() == userid) {
				return getUsersMeetings(u);
			}
		}
		return null;
	}
	
	public static List<Appointment> getLoggedInUsersAppointments() {
		if(getloggedInUser() != null) {
			return getUsersAppointments(getloggedInUser());
		}
		return null;
	}
	
	public static List<Meeting> getLoggedInUsersMeetings() {
		if(getloggedInUser() != null) {
			return getUsersMeetings(getloggedInUser());
		}
		return null;
	}
	
	public static List<Appointment> getUpComingAppointmentsAndMeetings() {
		List<Appointment> comingAppointments = new ArrayList<Appointment>();
		Calendar cal = Calendar.getInstance();
		for(Appointment a: getLoggedInUsersAppointments()) {
			if(a.getReservation().getEndTime().compareTo(cal) >= 0) {
				comingAppointments.add(a);
			}
		}
		for(Meeting a: getLoggedInUsersMeetings()) {
			if(a.getReservation().getEndTime().compareTo(cal) >= 0) {
				if(a.getOwner() == loggedInUser || a.getParticipants().contains(loggedInUser))
					comingAppointments.add(a);
			}
		}
		return comingAppointments;
	}
	
	// --------------------------   property change support   --------------------------- //
	private static PropertyChangeSupport changeSupport = new PropertyChangeSupport(new Storage());
	
	public static void updateUI() {
		changeSupport.firePropertyChange("updateUI", null, null);
	}
	
	public static void addListener(PropertyChangeListener listener) {
		changeSupport.addPropertyChangeListener(listener);
	}
	
	public static void removeListener(PropertyChangeListener listener) {
		changeSupport.removePropertyChangeListener(listener);
	}
}